package top.bug.blog.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import top.bug.blog.constant.CommonConstants;
import top.bug.blog.entity.dto.common.BatchRequest;
import top.bug.blog.entity.po.SensitiveWord;
import top.bug.blog.entity.po.User;
import top.bug.blog.enums.ErrorCode;
import top.bug.blog.exception.BussinessException;
import top.bug.blog.mapper.SensitiveWordMapper;
import top.bug.blog.mapper.UserMapper;
import top.bug.blog.service.SensitiveWordFilterService;
import top.bug.blog.utils.StrUtils;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

import static top.bug.blog.utils.StrUtils.isNotBlank;

/**
 * @author <a href="https://github.com/jiusi66">九思.</a>
 * @email 10837907@qq.com
 * @from <a href="https://www.52bug.top">递归茶馆-www.52bug.top</a>
 */
@Service
@Slf4j
public class SensitiveWordFilterServiceImpl implements SensitiveWordFilterService {

    @Resource
    private SensitiveWordMapper sensitiveWordMapper;

    @Resource
    private UserMapper userMapper;

    /**
     * 添加一个审核标记的ThreadLocal
     */
    private static final ThreadLocal<Boolean> reviewRequired = new ThreadLocal<>();
    private static final ThreadLocal<List<String>> reviewWords = new ThreadLocal<>();

    /**
     * DFA算法核心数据结构
     */
    private final Map<Character, DFANode> dfaRoot = new ConcurrentHashMap<>();
    /**
     * 替换词映射
     */
    private Map<String, String> replaceWordMap;

    /**
     * DFA节点类
     */
    @Data
    private static class DFANode {
        // 状态转移：字符 -> 下一个节点
        private Map<Character, DFANode> nextNodes = new HashMap<>();

        // 节点属性
        private boolean isEnd = false;
        private String wordType;
        private String replaceWord;
    }

    @PostConstruct
    public void initSensitiveWords() {
        refreshSensitiveWords();
    }

    @Override
    public void refreshSensitiveWords() {
        List<SensitiveWord> words = sensitiveWordMapper.selectList(
                new LambdaQueryWrapper<SensitiveWord>()
                        .eq(SensitiveWord::getStatus, "1")
                        .eq(SensitiveWord::getIsDelete, "0"));

        // 构建替换词映射
        this.replaceWordMap = words.stream()
                .filter(word -> "2".equals(word.getWordType()))
                .collect(Collectors.toMap(
                        SensitiveWord::getWord,
                        word -> StringUtils.isNotBlank(word.getReplaceWord()) ?
                                word.getReplaceWord() : "***"
                ));

        // 清空并重建DFA模型
        dfaRoot.clear();
        for (SensitiveWord word : words) {
            addWordToDFA(word.getWord(), word.getWordType());
        }
        log.info("DFA敏感词过滤器初始化完成，共加载{}个敏感词", words.size());
    }

    @Override
    public Page<SensitiveWord> getList(SensitiveWord queryRequest) {
        Page<SensitiveWord> page = new Page<>(1, 10);
        String word = queryRequest.getWord();
        String replaceWord = queryRequest.getReplaceWord();
        String wordType = queryRequest.getWordType();
        String status = queryRequest.getStatus();
        LambdaQueryWrapper<SensitiveWord> queryWrapper = new LambdaQueryWrapper<SensitiveWord>()
                .like(isNotBlank(word), SensitiveWord::getWord, word)
                .like(isNotBlank(replaceWord), SensitiveWord::getReplaceWord, replaceWord)
                .eq(isNotBlank(wordType), SensitiveWord::getWordType, wordType)
                .eq(isNotBlank(status), SensitiveWord::getStatus, status);
        sensitiveWordMapper.selectPage(page, queryWrapper);
        for (SensitiveWord record : page.getRecords()) {
            String createBy = record.getCreateBy();
            User user = userMapper.selectById(createBy);
            if (null == user) {
                continue;
            }
            record.setCreateUserName(user.getNickname());
        }
        return page;
    }

    @Override
    public Boolean add(SensitiveWord addRequest) {
        if (null == addRequest) {
            throw new BussinessException(ErrorCode.PARAM_NOT_COMPLETE);
        }
        // 必填项校验
        String wordType = addRequest.getWordType();
        String word = addRequest.getWord();
        String status = addRequest.getStatus();
        // 敏感词/替换词不能全部为空
        if (StrUtils.isAnyBlank(word, wordType)) {
            throw new BussinessException(ErrorCode.PARAM_NOT_COMPLETE);
        }
        SensitiveWord sensitiveWord = new SensitiveWord();
        BeanUtil.copyProperties(addRequest, sensitiveWord);
        // 默认值填充
        if (StrUtil.isBlank(status)) {
            sensitiveWord.setStatus(CommonConstants.STATUS_ENABLE);
        }
        // 保存（唯一性由数据库层面进行控制）
        int save = 0;
        try {
            save = sensitiveWordMapper.insert(sensitiveWord);
            refreshSensitiveWords();
        } catch (DuplicateKeyException e) {
            throw new BussinessException(ErrorCode.DATA_ALREADY_EXISTED);
        }
        return save > 0;
    }

    @Override
    public Boolean edit(SensitiveWord updateRequest) {
        if (null == updateRequest || StrUtil.isEmpty(updateRequest.getId())) {
            throw new BussinessException(ErrorCode.PARAM_NOT_COMPLETE);
        }
        SensitiveWord sensitiveWord = new SensitiveWord();
        BeanUtil.copyProperties(updateRequest, sensitiveWord);
        int count = sensitiveWordMapper.updateById(sensitiveWord);
        refreshSensitiveWords();
        return count > 0;
    }

    @Override
    public Boolean delete(BatchRequest batchRequest) {
        List<String> ids = batchRequest.getIds();
        if (CollUtil.isEmpty(ids)) {
            throw new BussinessException(ErrorCode.PARAM_NOT_COMPLETE);
        }
        int count = sensitiveWordMapper.deleteByIds(ids);
        refreshSensitiveWords();
        return count == ids.size();
    }

    /**
     * 修复后的添加单词到DFA模型方法
     */
    private void addWordToDFA(String word, String wordType) {
        if (StringUtils.isBlank(word)) {
            return;
        }

        Map<Character, DFANode> currentMap = dfaRoot;
        for (int i = 0; i < word.length(); i++) {
            char keyChar = word.charAt(i);
            DFANode node = currentMap.get(keyChar);

            if (node == null) {
                // 创建新节点
                node = new DFANode();
                currentMap.put(keyChar, node);
            }

            // 准备下一层映射
            if (node.getNextNodes() == null) {
                node.setNextNodes(new HashMap<>());
            }
            currentMap = node.getNextNodes();

            // 如果是单词的最后一个字符
            if (i == word.length() - 1) {
                node.setEnd(true);
                node.setWordType(wordType);

                // 如果是替换词，设置替换内容
                if ("2".equals(wordType)) {
                    node.setReplaceWord(replaceWordMap.getOrDefault(word, "***"));
                }
            }
        }
    }

    @Override
    public String filter(String text) throws BussinessException {
        if (StringUtils.isBlank(text)) {
            return text;
        }

        // 重置审核标记
        reviewRequired.set(false);
        reviewWords.set(new ArrayList<>());

        StringBuilder result = new StringBuilder();
        int length = text.length();
        int i = 0;

        while (i < length) {
            Map<Character, DFANode> currentMap = dfaRoot;
            DFANode endNode = null;
            int endIndex = -1;
            int j = i;

            // 查找最长的敏感词匹配
            while (j < length && currentMap != null) {
                char c = text.charAt(j);
                DFANode node = currentMap.get(c);

                if (node == null) {
                    break;
                }

                if (node.isEnd()) {
                    endNode = node;
                    endIndex = j;
                }

                currentMap = node.getNextNodes();
                j++;
            }

            if (endNode != null) {
                // 找到敏感词，根据类型处理
                String sensitiveWord = text.substring(i, endIndex + 1);
                switch (endNode.getWordType()) {
                    // 禁用词
                    case "1":
                        throw new BussinessException(ErrorCode.PARAM_IS_INVALID,
                                "内容包含禁用词: " + sensitiveWord);
                        // 替换词
                    case "2":
                        result.append(endNode.getReplaceWord());
                        break;
                    // 审核词
                    case "3":
                        result.append(sensitiveWord);
                        markForReview(sensitiveWord);
                        break;
                    default:
                        result.append(sensitiveWord);
                }
                i = endIndex + 1;
            } else {
                // 没有找到敏感词，添加当前字符
                result.append(text.charAt(i));
                i++;
            }
        }

        return result.toString();
    }

    @Override
    public boolean containsSensitiveWord(String text) {
        if (StringUtils.isBlank(text)) {
            return false;
        }

        int length = text.length();
        for (int i = 0; i < length; i++) {
            Map<Character, DFANode> currentMap = dfaRoot;
            int j = i;

            while (j < length && currentMap != null) {
                char c = text.charAt(j);
                DFANode node = currentMap.get(c);

                if (node == null) {
                    break;
                }

                if (node.isEnd()) {
                    return true;
                }

                currentMap = node.getNextNodes();
                j++;
            }
        }

        return false;
    }

    @Override
    public boolean isReviewRequired() {
        return Boolean.TRUE.equals(reviewRequired.get());
    }

    @Override
    public List<String> getReviewWords() {
        List<String> words = reviewWords.get();
        return words != null ? words : new ArrayList<>();
    }

    @Override
    public void clearReviewContext() {
        reviewRequired.remove();
        reviewWords.remove();
    }

    /**
     * 判断是否为特殊字符
     */
    private boolean isSymbol(char c) {
        // 0x2E80-0x9FFF 是东亚文字范围
        return !Character.isLetterOrDigit(c) && (c < 0x2E80 || c > 0x9FFF);
    }

    /**
     * 标记需要审核的内容
     */
    private void markForReview(String sensitiveWord) {
        log.info("发现审核词: {}, 需要人工审核", sensitiveWord);

        // 设置审核标记
        reviewRequired.set(true);

        // 记录审核词
        List<String> words = reviewWords.get();
        if (words == null) {
            words = new ArrayList<>();
            reviewWords.set(words);
        }
        words.add(sensitiveWord);
    }
}